/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: stack backtrace for riscv64 arch
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2022-07-28     JasonHu           Init
 */

#include <base/backtrace.h>
#define NX_LOG_NAME "rv64:backtrace"
#include <base/log.h>

/**
 * function call stack:
 * 
 * High address
 * +------------+ <--- current fp
 * |ra          | return address
 * |fp          | old fp
 * +------------+ <--- sp
 * Lower address
 */
NX_PRIVATE NX_Size NX_HalStackBacktrace(void ** buffer, NX_Size size, NX_Addr fp, NX_Addr stackTop)
{
    int i = 0;
    NX_Size n = 0;

    NX_U64 ra;

    if (!fp)
    {
        NX_CASM ("mv %0, s0" : "=r" (fp) );
    }

    for(i = 0; i < size && fp; i++)
    {
        /* check ebp under stack top */
        if (stackTop && fp >= stackTop)
        {
            break;
        }

        ra = *((NX_U64 *)(fp - 8));
        fp = *((NX_U64 *)(fp - 16));

        buffer[i] = (void *)ra; /* save call addr */
        n++;
        
        /* check eip in kernel code range */
        if (ra < NX_KernelGetSegmentStart("text") || ra >= NX_KernelGetSegmentEnd("bss"))
        {
            break;
        }
    }
    return n;
}

NX_INTERFACE struct NX_StackBacktraceOps gStackBacktraceOpsInterface = 
{
    .backtrace      = NX_HalStackBacktrace,
};
